import { type ChangeEvent, type MouseEvent, useContext, useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import type { TBody } from '@/types';
import {
  createComment,
  createFavourite,
  createFollow,
  postCancelFavourite,
  postCancelFollow,
  postCancelLike,
  postFavourite,
  postFollow,
  postLike,
  removeFavourite,
  removeFollow,
} from '@/services/api';
import clipboard from 'clipboard';
import useModal from '@/hooks/useModal';
import sanitizeHtml from 'sanitize-html';
import useToast, { LoginReminderContent } from 'hooks/useToast';
import { useRouter } from 'next/navigation';
import { PostIdPageContext } from '@/contexts/post-id';
import Spinner from '@/app/[locale]/component/spinner/spinner';

export default function ButtonAreaPostIdH5Page() {
  const {
    source: { postDetails },
  } = useContext(PostIdPageContext)!;
  const {
    id,
    name,
    like = false,
    likeNum = 0,
    follow = false,
    followNum = 0,
    favourite = false,
    favouriteNum = 0,
    alias,
  } = {
    id: postDetails.basic.id,
    name: postDetails.basic.name,
    like: postDetails.isLike,
    likeNum: postDetails.details.likeCount,
    follow: postDetails.isFollow,
    followNum: postDetails.details.followCount,
    favourite: postDetails.isFavourite,
    favouriteNum: postDetails.details.favoriteCount,
    alias: postDetails.user.alias,
  };

  return (
    <div className="vstack gap-3 justify-content-around">
      <div className="hstack gap-4 justify-content-center">
        <CommentBtn id={id} alias={alias} />
        <LikeBtn id={id} like={like} likeNum={likeNum} />
        <FollowBtn id={id} follow={follow} followNum={followNum} />
      </div>
      <div className="hstack gap-4 justify-content-center">
        <ShareBtn name={name} />
        <FavouriteBtn
          id={id}
          favourite={favourite}
          favouriteNum={favouriteNum}
        />
      </div>
    </div>
  );
}

const CommentBtn = ({ id, alias }: { id: number; alias: string }) => {
  const { translatedFields } = useContext(PostIdPageContext)!;
  const { showModal, hideModal } = useModal();

  function onClickComment() {
    const modal = showModal({
      title: `@${alias}`,
      content: (
        <CommentModal
          id={id}
          callback={() => {
            hideModal(modal);
          }}
        />
      ),
      isShowFooter: false,
    });
  }

  return (
    <button onClick={onClickComment} type="button" className="btn">
      <i className="bi bi-reply me-2"></i>
      {translatedFields.comment}
    </button>
  );
};

const CommentModal = ({
  id,
  callback,
}: {
  id: number;
  callback?: () => void;
}) => {
  const {
    source: { path },
    translatedFields,
  } = useContext(PostIdPageContext)!;
  const [commentContent, setCommentContent] = useState('');
  const { show } = useToast();
  const router = useRouter();

  const createCommentMutation = useMutation(createComment);

  async function onClickPostComment(e: MouseEvent<HTMLButtonElement>) {
    try {
      e.stopPropagation();
      e.preventDefault();

      if (!path.user) {
        show({
          type: 'PRIMARY',
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      if (!commentContent.trim()) {
        setCommentContent('');
        show({
          type: 'DANGER',
          message: translatedFields.replyContentEmptyError,
        });
        return;
      }

      const content = sanitizeHtml(commentContent);
      if (!content) {
        setCommentContent('');
        show({
          type: 'DANGER',
          message: translatedFields.replyContentEmptyError,
        });
        return;
      }

      await createCommentMutation.mutateAsync({
        data: {
          postId: id,
          content,
        },
      });

      setCommentContent('');
      show({
        type: 'SUCCESS',
        message: translatedFields.replyCompleted,
      });

      if (callback) {
        callback();
      }

      router.refresh();
    } catch (e) {
      createCommentMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  function onChangeCommentContent(e: ChangeEvent<HTMLTextAreaElement>) {
    setCommentContent(e.target.value);
  }

  return (
    <div className="row">
      <div className="col">
        <form className="vstack gap-4">
          <textarea
            name="commentContent"
            className="form-control"
            rows={5}
            placeholder={translatedFields.enterReply}
            value={commentContent}
            onChange={onChangeCommentContent}
          ></textarea>
          <button
            onClick={onClickPostComment}
            disabled={createCommentMutation.isLoading || !commentContent}
            type="button"
            className="btn btn-outline-primary"
          >
            {createCommentMutation.isLoading ? (
              <Spinner classs="me-2" />
            ) : (
              <i className="bi bi-cursor me-2"></i>
            )}
            {translatedFields.postReply}
          </button>
        </form>
      </div>
    </div>
  );
};

const LikeBtn = ({
  id,
  like = false,
  likeNum = 0,
}: {
  id: number;
  like?: boolean;
  likeNum?: number;
}) => {
  const {
    source: { path },
    translatedFields,
  } = useContext(PostIdPageContext)!;
  const { show } = useToast();
  const [isLike, setIsLike] = useState(like);
  const [likeCount, setLikeCount] = useState(likeNum);

  const likeMutation = useMutation(async (variables: TBody<void>) => {
    await postLike(variables);
  });
  const cancelLikeMutation = useMutation(async (variables: TBody<void>) => {
    await postCancelLike(variables);
  });

  async function onClickLike() {
    try {
      if (!path.user) {
        show({
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      let message;
      if (isLike) {
        await cancelLikeMutation.mutateAsync({ id });
        message = translatedFields.alreadyCancelled;
        setIsLike(false);
        setLikeCount(likeCount - 1);
      } else {
        await likeMutation.mutateAsync({ id });
        message = translatedFields.alreadyLiked;
        setIsLike(true);
        setLikeCount(likeCount + 1);
      }

      show({
        type: 'SUCCESS',
        message,
      });
    } catch (e) {
      if (isLike) {
        cancelLikeMutation.reset();
      } else {
        likeMutation.reset();
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <button
      disabled={likeMutation.isLoading || cancelLikeMutation.isLoading}
      onClick={onClickLike}
      type="button"
      className="btn position-relative"
    >
      {isLike ? (
        <span>
          {cancelLikeMutation.isLoading ? (
            <Spinner classs="me-2" />
          ) : (
            <i className="bi bi-hand-thumbs-up-fill me-2"></i>
          )}
          {translatedFields.alreadyLiked}
        </span>
      ) : (
        <span>
          {likeMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-hand-thumbs-up me-2"></i>
          )}
          {translatedFields.like}
        </span>
      )}

      {likeCount > 0 && (
        <span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-secondary bg-opacity-75">
          {likeCount > 99 ? '99+' : likeCount > 999 ? '999+' : likeCount}
          <span className="visually-hidden">{translatedFields.likeCount}</span>
        </span>
      )}
    </button>
  );
};

const FollowBtn = ({
  id,
  follow = false,
  followNum = 0,
}: {
  id: number;
  follow?: boolean;
  followNum?: number;
}) => {
  const {
    source: { path },
    translatedFields,
  } = useContext(PostIdPageContext)!;
  const { show } = useToast();
  const [isFollow, setIsFollow] = useState(follow);
  const [followCount, setFollowCount] = useState(followNum);

  const followMutation = useMutation(async (variables: TBody<void>) => {
    await postFollow(variables);
  });
  const cancelFollowMutation = useMutation(async (variables: TBody<void>) => {
    await postCancelFollow(variables);
  });
  const createFollowMutation = useMutation(async (variables: TBody<void>) => {
    await createFollow(variables);
  });
  const removeFollowMutation = useMutation(async (variables: TBody<void>) => {
    await removeFollow(variables);
  });

  async function onClickFollow() {
    try {
      if (!path.user) {
        show({
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      let message;

      if (isFollow) {
        await Promise.all([
          removeFollowMutation.mutateAsync({ id }),
          cancelFollowMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyCancelled;
        setIsFollow(false);
        setFollowCount(followCount - 1);
      } else {
        await Promise.all([
          createFollowMutation.mutateAsync({ id }),
          followMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyFollowed;
        setIsFollow(true);
        setFollowCount(followCount + 1);
      }

      show({
        type: 'SUCCESS',
        message,
      });
    } catch (e) {
      if (isFollow) {
        removeFollowMutation.reset();
        cancelFollowMutation.reset();
      } else {
        createFollowMutation.reset();
        followMutation.reset();
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <button
      disabled={
        createFollowMutation.isLoading ||
        followMutation.isLoading ||
        removeFollowMutation.isLoading ||
        cancelFollowMutation.isLoading
      }
      onClick={onClickFollow}
      type="button"
      className="btn position-relative"
    >
      {isFollow ? (
        <span>
          {removeFollowMutation.isLoading || cancelFollowMutation.isLoading ? (
            <Spinner classs="me-2" />
          ) : (
            <i className="bi bi-bell-fill me-2"></i>
          )}
          {translatedFields.alreadyFollowed}
        </span>
      ) : (
        <span>
          {createFollowMutation.isLoading || followMutation.isLoading ? (
            <Spinner classs="me-2" />
          ) : (
            <i className="bi bi-bell me-2"></i>
          )}
          {translatedFields.follow}
        </span>
      )}

      {followCount > 0 && (
        <span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-secondary bg-opacity-75">
          {followCount > 99 ? '99+' : followCount > 999 ? '999+' : followCount}
          <span className="visually-hidden">
            {translatedFields.followCount}
          </span>
        </span>
      )}
    </button>
  );
};

const ShareBtn = ({ name }: { name: string }) => {
  const { translatedFields } = useContext(PostIdPageContext)!;
  const { show } = useToast();

  function onClickShare() {
    clipboard.copy(`[${name}](${location.href})`);
    show({
      type: 'SUCCESS',
      message: translatedFields.copyCompleted,
    });
  }

  return (
    <>
      <button onClick={onClickShare} type="button" className="btn">
        <span>
          <i className="bi bi-share me-2"></i>
          {translatedFields.share}
        </span>
      </button>
    </>
  );
};

const FavouriteBtn = ({
  id,
  favourite = false,
  favouriteNum = 0,
}: {
  id: number;
  favourite?: boolean;
  favouriteNum?: number;
}) => {
  const {
    source: { path },
    translatedFields,
  } = useContext(PostIdPageContext)!;
  const { show } = useToast();
  const [isFavourite, setIsFavourite] = useState(favourite);
  const [favoriteCount, setFavoriteCount] = useState(favouriteNum);

  const favouriteMutation = useMutation(async (variables: TBody<void>) => {
    await postFavourite(variables);
  });
  const cancelFavouriteMutation = useMutation(
    async (variables: TBody<void>) => {
      await postCancelFavourite(variables);
    },
  );
  const createFavouriteMutation = useMutation(
    async (variables: TBody<void>) => {
      await createFavourite(variables);
    },
  );
  const removeFavouriteMutation = useMutation(
    async (variables: TBody<void>) => {
      await removeFavourite(variables);
    },
  );

  async function onClickFavourite() {
    try {
      if (!path.user) {
        show({
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      let message;

      if (isFavourite) {
        await Promise.all([
          removeFavouriteMutation.mutateAsync({ id }),
          cancelFavouriteMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyCancelled;
        setIsFavourite(false);
        setFavoriteCount(favoriteCount - 1);
      } else {
        await Promise.all([
          createFavouriteMutation.mutateAsync({ id }),
          favouriteMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyBookmarked;
        setIsFavourite(true);
        setFavoriteCount(favoriteCount + 1);
      }

      show({
        type: 'SUCCESS',
        message,
      });
    } catch (e) {
      if (isFavourite) {
        removeFavouriteMutation.reset();
        cancelFavouriteMutation.reset();
      } else {
        createFavouriteMutation.reset();
        favouriteMutation.reset();
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <button
      disabled={
        createFavouriteMutation.isLoading ||
        favouriteMutation.isLoading ||
        removeFavouriteMutation.isLoading ||
        cancelFavouriteMutation.isLoading
      }
      onClick={onClickFavourite}
      type="button"
      className="btn position-relative"
    >
      {isFavourite ? (
        <span>
          {removeFavouriteMutation.isLoading ||
          cancelFavouriteMutation.isLoading ? (
            <Spinner classs="me-2" />
          ) : (
            <i className="bi bi-star-fill me-2"></i>
          )}
          {translatedFields.alreadyBookmarked}
        </span>
      ) : (
        <span>
          {createFavouriteMutation.isLoading || favouriteMutation.isLoading ? (
            <Spinner classs="me-2" />
          ) : (
            <i className="bi bi-star me-2"></i>
          )}
          {translatedFields.bookmark}
        </span>
      )}

      {favoriteCount > 0 && (
        <span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-secondary bg-opacity-75">
          {favoriteCount > 99
            ? '99+'
            : favoriteCount > 999
            ? '999+'
            : favoriteCount}
          <span className="visually-hidden">
            {translatedFields.bookmarkCount}
          </span>
        </span>
      )}
    </button>
  );
};
